﻿using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Drawing;

namespace CopyrightLib
{
    /// <summary>
    /// Входная точка для копирастии
    /// </summary>
    public class CopyrightMaker
    {
        #region Константы

        private const string MarkName = "mark.png";

        private const string settingsName = "settings.xml";

        public const string BackupExtension = ".mbk";

        public const string ApplicationDirName = "photomark";

        /// <summary>
        /// Для адекватного сохранения данных фото
        /// </summary>
        public const string TmpExtension = ".tmp";

        #endregion

        /// <summary>
        /// Список файлов
        /// </summary>
        public List<string> FileNames { get; set; }

        /// <summary>
        /// Рабочая папка
        /// </summary>
        public string DirectoryName { get; set; }

        /// <summary>
        /// Настройки (в итоге название директории с ними)
        /// </summary>
        public string SettingsName { get; set; }

        /// <summary>
        /// Брать просто все картинки из папки
        /// </summary>
        public bool InAllDirectory { get; set; }

        /// <summary>
        /// Нужно ли делать бэкап
        /// </summary>
        public bool NeedBackup { get; set; }

        /// <summary>
        /// Прогресса отметка это
        /// </summary>
        public event EventHandler<MessageEventArgs> Progress;


        #region Методы наружу

        /// <summary>
        /// Помечает согласно настройкам фото
        /// </summary>
        public void MakeCopyright()
        {
            var mark = new Bitmap(Path.Combine(GetSettingsDirectory, MarkName));
            var settings = new MarkSettings(Path.Combine(GetSettingsDirectory, settingsName));
            if (InAllDirectory)
            {
               FileNames = GetFilenamesInDirectory();
            }
            if (NeedBackup)
            {
                 foreach (string fileName in FileNames)
                 {
                     File.Copy(Path.Combine(DirectoryName, fileName),
                         Path.Combine(DirectoryName, fileName) + BackupExtension, true);
                 }
            }

            int procFileCount = 0;
            foreach (string fileName in FileNames)
            {
                var bmp = new Bitmap(fileName);
                Graphics g = Graphics.FromImage(bmp);

                // тут применяем аццкие настройки
                // картинко
                if (settings.MarkType == 0)
                {
                    g.DrawImage(mark, GetMarkPosition(bmp, mark, settings));
                }
                // текст в ртф
                else
                {
                    var rtBox = new RichTextBoxPrintCtrl {BackColor = Color.White, Rtf = settings.Text};
                    var textBmp = new Bitmap(rtBox.ClientSize.Width + 30, rtBox.PreferredSize.Height + 10);
                    textBmp.SetResolution(bmp.HorizontalResolution, bmp.VerticalResolution);
                    Graphics textg = Graphics.FromImage(textBmp);

                    rtBox.Print(0, rtBox.Text.Length, textg, 
                        new Rectangle(rtBox.Location, new Size(rtBox.ClientSize.Width + 30, rtBox.PreferredSize.Height + 10)));
                    textg.Dispose();

                    textBmp.MakeTransparent(Color.White);
                    g.DrawImage(textBmp, GetMarkPosition(bmp, textBmp, settings));
                }
                g.Dispose();

                // сохраняем во временный файл
                // с потоками не получается, ибо не всегда сохраняет доп инфу
                bmp.Save(fileName + TmpExtension);
                // освобождаем настоящий файл его
                bmp.Dispose();

                // восстанавливаем из темпа в настоящий
                File.Copy(Path.Combine(DirectoryName, fileName + TmpExtension), 
                    Path.Combine(DirectoryName, fileName), true);
                // темп не нужен, удаляем
                File.Delete(Path.Combine(DirectoryName, fileName + TmpExtension));


                procFileCount++;
                if (Progress != null)
                {
                    Progress(this, new MessageEventArgs(String.Format("Помечено {0} из {1} фото",
                        procFileCount, FileNames.Count)));
                }
            }
        }

        /// <summary>
        /// Восстанавливает фото из бекапа
        /// </summary>
        public void Restore()
        {
            var di = new DirectoryInfo(DirectoryName);
            foreach (var fileInfo in di.EnumerateFiles("*" + BackupExtension))
            {
                File.Copy(Path.Combine(DirectoryName, fileInfo.Name),
                    Path.Combine(DirectoryName, fileInfo.Name.Substring(0, fileInfo.Name.IndexOf(BackupExtension))));
                File.Delete(Path.Combine(DirectoryName, fileInfo.Name));
            }
        }

        #endregion

        #region Вспомогательные методы

        private string GetSettingsDirectory
        {
            get
            {
                return Path.Combine(
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), ApplicationDirName),
                    SettingsName);
            }
        }

        private List<string> GetFilenamesInDirectory()
        {
            return (new DirectoryInfo(DirectoryName).EnumerateFiles().Where(
                fileInfo => IsSupportedExtension(fileInfo.Extension)).Select(fileInfo => fileInfo.FullName)).ToList();
        }

        private static bool IsSupportedExtension(string ext)
        {
            string upperExt = ext.ToUpper();
            //GDI+ supports the following file formats: BMP, GIF, EXIF, JPG, PNG and TIFF.)
            return upperExt == ".BMP" || upperExt == ".GIF" || upperExt == ".EXIF" || 
                upperExt == ".JPG" || upperExt == ".PNG" || upperExt == ".TIFF";
        }

        private static Point GetMarkPosition(Bitmap bmp, Bitmap mark, MarkSettings settings)
        {
            int x;
            if (settings.HorizontalAlignment == HorizontalAlignment.Left)
                x = settings.Margin.Left;
            else if (settings.HorizontalAlignment == HorizontalAlignment.Right)
                x = bmp.Width - mark.Width - settings.Margin.Right;
            else
                x = bmp.Width / 2 - mark.Width / 2;

            int y;
            if (settings.VerticalAlignment == VerticalAlignment.Up)
                y = settings.Margin.Up;
            else if (settings.VerticalAlignment == VerticalAlignment.Down)
                y = bmp.Height - mark.Height - settings.Margin.Down;
            else
                y = bmp.Height / 2 - mark.Height / 2;

            return new Point(x,y);
        }

        #endregion

        #region Кодировщики

        private static ImageFormat GetFormat(string imgFileName)
        {
            int idx = imgFileName.LastIndexOf('.');
            string ext = imgFileName.Substring(idx+1);
                       //GDI+ supports the following file formats: BMP, GIF, EXIF, JPG, PNG and TIFF.)
            switch (ext.ToUpper())
            {
                case "BMP":
                    return ImageFormat.Bmp;
                case "GIF":
                    return ImageFormat.Gif;
                case "EXIF":
                    return ImageFormat.Exif;
                case "JPG":
                    return ImageFormat.Jpeg;
                case "PNG":
                    return ImageFormat.Png;
                case "TIFF":
                    return ImageFormat.Tiff;
                default:
                    return ImageFormat.Png;
            }
        }

        private ImageCodecInfo GetEncoder(string imgFileName)
        {
            ImageFormat format = GetFormat(imgFileName);
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
            return codecs.FirstOrDefault(codec => codec.FormatID == format.Guid);
        }

        #endregion
    }


}
